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 | // -*- mode: c++ -*- |
michael@0 | 2 | |
michael@0 | 3 | // Copyright (c) 2010, Google Inc. |
michael@0 | 4 | // All rights reserved. |
michael@0 | 5 | // |
michael@0 | 6 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 7 | // modification, are permitted provided that the following conditions are |
michael@0 | 8 | // met: |
michael@0 | 9 | // |
michael@0 | 10 | // * Redistributions of source code must retain the above copyright |
michael@0 | 11 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 12 | // * Redistributions in binary form must reproduce the above |
michael@0 | 13 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 14 | // in the documentation and/or other materials provided with the |
michael@0 | 15 | // distribution. |
michael@0 | 16 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 17 | // contributors may be used to endorse or promote products derived from |
michael@0 | 18 | // this software without specific prior written permission. |
michael@0 | 19 | // |
michael@0 | 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 31 | |
michael@0 | 32 | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
michael@0 | 33 | |
michael@0 | 34 | // Implementation of google_breakpad::DwarfCFIToModule. |
michael@0 | 35 | // See dwarf_cfi_to_module.h for details. |
michael@0 | 36 | |
michael@0 | 37 | #include <sstream> |
michael@0 | 38 | #include <iomanip> |
michael@0 | 39 | |
michael@0 | 40 | #include "common/dwarf_cfi_to_module.h" |
michael@0 | 41 | #include "common/logging.h" |
michael@0 | 42 | |
michael@0 | 43 | namespace google_breakpad { |
michael@0 | 44 | |
michael@0 | 45 | using std::ostringstream; |
michael@0 | 46 | |
michael@0 | 47 | vector<const UniqueString*> DwarfCFIToModule::RegisterNames::MakeVector( |
michael@0 | 48 | const char* const* strings, |
michael@0 | 49 | size_t size) { |
michael@0 | 50 | vector<const UniqueString*> names(size, NULL); |
michael@0 | 51 | for (size_t i = 0; i < size; ++i) { |
michael@0 | 52 | names[i] = ToUniqueString(strings[i]); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | return names; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | vector<const UniqueString*> DwarfCFIToModule::RegisterNames::I386() { |
michael@0 | 59 | static const char *const names[] = { |
michael@0 | 60 | "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", |
michael@0 | 61 | "$eip", "$eflags", "$unused1", |
michael@0 | 62 | "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", |
michael@0 | 63 | "$unused2", "$unused3", |
michael@0 | 64 | "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", |
michael@0 | 65 | "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", |
michael@0 | 66 | "$fcw", "$fsw", "$mxcsr", |
michael@0 | 67 | "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", |
michael@0 | 68 | "$tr", "$ldtr" |
michael@0 | 69 | }; |
michael@0 | 70 | |
michael@0 | 71 | return MakeVector(names, sizeof(names) / sizeof(names[0])); |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | vector<const UniqueString*> DwarfCFIToModule::RegisterNames::X86_64() { |
michael@0 | 75 | static const char *const names[] = { |
michael@0 | 76 | "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", |
michael@0 | 77 | "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", |
michael@0 | 78 | "$rip", |
michael@0 | 79 | "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", |
michael@0 | 80 | "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", |
michael@0 | 81 | "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", |
michael@0 | 82 | "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", |
michael@0 | 83 | "$rflags", |
michael@0 | 84 | "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", |
michael@0 | 85 | "$fs.base", "$gs.base", "$unused3", "$unused4", |
michael@0 | 86 | "$tr", "$ldtr", |
michael@0 | 87 | "$mxcsr", "$fcw", "$fsw" |
michael@0 | 88 | }; |
michael@0 | 89 | |
michael@0 | 90 | return MakeVector(names, sizeof(names) / sizeof(names[0])); |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | // Per ARM IHI 0040A, section 3.1 |
michael@0 | 94 | vector<const UniqueString*> DwarfCFIToModule::RegisterNames::ARM() { |
michael@0 | 95 | static const char *const names[] = { |
michael@0 | 96 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
michael@0 | 97 | "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", |
michael@0 | 98 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
michael@0 | 99 | "fps", "cpsr", "", "", "", "", "", "", |
michael@0 | 100 | "", "", "", "", "", "", "", "", |
michael@0 | 101 | "", "", "", "", "", "", "", "", |
michael@0 | 102 | "", "", "", "", "", "", "", "", |
michael@0 | 103 | "", "", "", "", "", "", "", "", |
michael@0 | 104 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
michael@0 | 105 | "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", |
michael@0 | 106 | "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", |
michael@0 | 107 | "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", |
michael@0 | 108 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" |
michael@0 | 109 | }; |
michael@0 | 110 | |
michael@0 | 111 | return MakeVector(names, sizeof(names) / sizeof(names[0])); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, |
michael@0 | 115 | uint8 version, const string &augmentation, |
michael@0 | 116 | unsigned return_address) { |
michael@0 | 117 | assert(!entry_); |
michael@0 | 118 | |
michael@0 | 119 | // If dwarf2reader::CallFrameInfo can handle this version and |
michael@0 | 120 | // augmentation, then we should be okay with that, so there's no |
michael@0 | 121 | // need to check them here. |
michael@0 | 122 | |
michael@0 | 123 | // Get ready to collect entries. |
michael@0 | 124 | entry_ = new Module::StackFrameEntry; |
michael@0 | 125 | entry_->address = address; |
michael@0 | 126 | entry_->size = length; |
michael@0 | 127 | entry_offset_ = offset; |
michael@0 | 128 | return_address_ = return_address; |
michael@0 | 129 | |
michael@0 | 130 | // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI |
michael@0 | 131 | // may not establish any rule for .ra if the return address column |
michael@0 | 132 | // is an ordinary register, and that register holds the return |
michael@0 | 133 | // address on entry to the function. So establish an initial .ra |
michael@0 | 134 | // rule citing the return address register. |
michael@0 | 135 | if (return_address_ < register_names_.size()) |
michael@0 | 136 | entry_->initial_rules[ustr__ZDra()] |
michael@0 | 137 | = Module::Expr(register_names_[return_address_], 0, false); |
michael@0 | 138 | |
michael@0 | 139 | return true; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | const UniqueString* DwarfCFIToModule::RegisterName(int i) { |
michael@0 | 143 | assert(entry_); |
michael@0 | 144 | if (i < 0) { |
michael@0 | 145 | assert(i == kCFARegister); |
michael@0 | 146 | return ustr__ZDcfa(); |
michael@0 | 147 | } |
michael@0 | 148 | unsigned reg = i; |
michael@0 | 149 | if (reg == return_address_) |
michael@0 | 150 | return ustr__ZDra(); |
michael@0 | 151 | |
michael@0 | 152 | // Ensure that a non-empty name exists for this register value. |
michael@0 | 153 | if (reg < register_names_.size() && register_names_[reg] != ustr__empty()) |
michael@0 | 154 | return register_names_[reg]; |
michael@0 | 155 | |
michael@0 | 156 | reporter_->UnnamedRegister(entry_offset_, reg); |
michael@0 | 157 | char buf[30]; |
michael@0 | 158 | sprintf(buf, "unnamed_register%u", reg); |
michael@0 | 159 | return ToUniqueString(buf); |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | void DwarfCFIToModule::Record(Module::Address address, int reg, |
michael@0 | 163 | const Module::Expr &rule) { |
michael@0 | 164 | assert(entry_); |
michael@0 | 165 | |
michael@0 | 166 | // Is this one of this entry's initial rules? |
michael@0 | 167 | if (address == entry_->address) |
michael@0 | 168 | entry_->initial_rules[RegisterName(reg)] = rule; |
michael@0 | 169 | // File it under the appropriate address. |
michael@0 | 170 | else |
michael@0 | 171 | entry_->rule_changes[address][RegisterName(reg)] = rule; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { |
michael@0 | 175 | reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); |
michael@0 | 176 | // Treat this as a non-fatal error. |
michael@0 | 177 | return true; |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { |
michael@0 | 181 | // reg + 0 |
michael@0 | 182 | Module::Expr rule |
michael@0 | 183 | = Module::Expr(RegisterName(reg), 0, false); |
michael@0 | 184 | Record(address, reg, rule); |
michael@0 | 185 | return true; |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, |
michael@0 | 189 | int base_register, long offset) { |
michael@0 | 190 | // *(base_register + offset) |
michael@0 | 191 | Module::Expr rule |
michael@0 | 192 | = Module::Expr(RegisterName(base_register), offset, true); |
michael@0 | 193 | Record(address, reg, rule); |
michael@0 | 194 | return true; |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, |
michael@0 | 198 | int base_register, long offset) { |
michael@0 | 199 | // base_register + offset |
michael@0 | 200 | Module::Expr rule |
michael@0 | 201 | = Module::Expr(RegisterName(base_register), offset, false); |
michael@0 | 202 | Record(address, reg, rule); |
michael@0 | 203 | return true; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, |
michael@0 | 207 | int base_register) { |
michael@0 | 208 | // base_register + 0 |
michael@0 | 209 | Module::Expr rule |
michael@0 | 210 | = Module::Expr(RegisterName(base_register), 0, false); |
michael@0 | 211 | Record(address, reg, rule); |
michael@0 | 212 | return true; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, |
michael@0 | 216 | const string &expression) { |
michael@0 | 217 | reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); |
michael@0 | 218 | // Treat this as a non-fatal error. |
michael@0 | 219 | return true; |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, |
michael@0 | 223 | const string &expression) { |
michael@0 | 224 | reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); |
michael@0 | 225 | // Treat this as a non-fatal error. |
michael@0 | 226 | return true; |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | bool DwarfCFIToModule::End() { |
michael@0 | 230 | module_->AddStackFrameEntry(entry_); |
michael@0 | 231 | entry_ = NULL; |
michael@0 | 232 | return true; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { |
michael@0 | 236 | BPLOG(INFO) << file_ << ", section '" << section_ |
michael@0 | 237 | << "': the call frame entry at offset 0x" |
michael@0 | 238 | << std::setbase(16) << offset << std::setbase(10) |
michael@0 | 239 | << " refers to register " << reg << ", whose name we don't know"; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | void DwarfCFIToModule::Reporter::UndefinedNotSupported( |
michael@0 | 243 | size_t offset, |
michael@0 | 244 | const UniqueString* reg) { |
michael@0 | 245 | BPLOG(INFO) << file_ << ", section '" << section_ |
michael@0 | 246 | << "': the call frame entry at offset 0x" |
michael@0 | 247 | << std::setbase(16) << offset << std::setbase(10) |
michael@0 | 248 | << " sets the rule for register '" << FromUniqueString(reg) |
michael@0 | 249 | << "' to 'undefined', but the Breakpad symbol file format cannot " |
michael@0 | 250 | << " express this"; |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | void DwarfCFIToModule::Reporter::ExpressionsNotSupported( |
michael@0 | 254 | size_t offset, |
michael@0 | 255 | const UniqueString* reg) { |
michael@0 | 256 | static uint64_t n_complaints = 0; // This isn't threadsafe |
michael@0 | 257 | n_complaints++; |
michael@0 | 258 | if (!is_power_of_2(n_complaints)) |
michael@0 | 259 | return; |
michael@0 | 260 | BPLOG(INFO) << file_ << ", section '" << section_ |
michael@0 | 261 | << "': the call frame entry at offset 0x" |
michael@0 | 262 | << std::setbase(16) << offset << std::setbase(10) |
michael@0 | 263 | << " uses a DWARF expression to describe how to recover register '" |
michael@0 | 264 | << FromUniqueString(reg) << "', but this translator cannot yet " |
michael@0 | 265 | << "translate DWARF expressions to Breakpad postfix expressions (shown " |
michael@0 | 266 | << n_complaints << " times)"; |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | } // namespace google_breakpad |