1 // -*- mode: c++ -*- 2 3 // Copyright (c) 2010, Google Inc. 4 // All rights reserved. 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com> 33 34 // Implementation of google_breakpad::DwarfCFIToModule. 35 // See dwarf_cfi_to_module.h for details. 36 37 #include <sstream> 38 39 #include "common/dwarf_cfi_to_module.h" 40 41 namespace google_breakpad { 42 43 using std::ostringstream; 44 45 vector<string> DwarfCFIToModule::RegisterNames::MakeVector( 46 const char * const *strings, 47 size_t size) { 48 vector<string> names(strings, strings + size); 49 return names; 50 } 51 52 vector<string> DwarfCFIToModule::RegisterNames::I386() { 53 static const char *const names[] = { 54 "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", 55 "$eip", "$eflags", "$unused1", 56 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", 57 "$unused2", "$unused3", 58 "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", 59 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", 60 "$fcw", "$fsw", "$mxcsr", 61 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", 62 "$tr", "$ldtr" 63 }; 64 65 return MakeVector(names, sizeof(names) / sizeof(names[0])); 66 } 67 68 vector<string> DwarfCFIToModule::RegisterNames::X86_64() { 69 static const char *const names[] = { 70 "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", 71 "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", 72 "$rip", 73 "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", 74 "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", 75 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", 76 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", 77 "$rflags", 78 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", 79 "$fs.base", "$gs.base", "$unused3", "$unused4", 80 "$tr", "$ldtr", 81 "$mxcsr", "$fcw", "$fsw" 82 }; 83 84 return MakeVector(names, sizeof(names) / sizeof(names[0])); 85 } 86 87 // Per ARM IHI 0040A, section 3.1 88 vector<string> DwarfCFIToModule::RegisterNames::ARM() { 89 static const char *const names[] = { 90 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 91 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", 92 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 93 "fps", "cpsr", "", "", "", "", "", "", 94 "", "", "", "", "", "", "", "", 95 "", "", "", "", "", "", "", "", 96 "", "", "", "", "", "", "", "", 97 "", "", "", "", "", "", "", "", 98 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 99 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", 100 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", 101 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", 102 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" 103 }; 104 105 return MakeVector(names, sizeof(names) / sizeof(names[0])); 106 } 107 108 // Per ARM IHI 0057A, section 3.1 109 vector<string> DwarfCFIToModule::RegisterNames::ARM64() { 110 static const char *const names[] = { 111 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 112 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 113 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 114 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", 115 "", "", "", "", "", "", "", "", 116 "", "", "", "", "", "", "", "", 117 "", "", "", "", "", "", "", "", 118 "", "", "", "", "", "", "", "", 119 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", 120 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", 121 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", 122 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" 123 }; 124 125 return MakeVector(names, sizeof(names) / sizeof(names[0])); 126 } 127 128 vector<string> DwarfCFIToModule::RegisterNames::MIPS() { 129 static const char* const kRegisterNames[] = { 130 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", 131 "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", 132 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", 133 "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", 134 "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5", 135 "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", 136 "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", 137 "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", 138 "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir" 139 }; 140 141 return MakeVector(kRegisterNames, 142 sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); 143 } 144 145 bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, 146 uint8 version, const string &augmentation, 147 unsigned return_address) { 148 assert(!entry_); 149 150 // If dwarf2reader::CallFrameInfo can handle this version and 151 // augmentation, then we should be okay with that, so there's no 152 // need to check them here. 153 154 // Get ready to collect entries. 155 entry_ = new Module::StackFrameEntry; 156 entry_->address = address; 157 entry_->size = length; 158 entry_offset_ = offset; 159 return_address_ = return_address; 160 161 // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI 162 // may not establish any rule for .ra if the return address column 163 // is an ordinary register, and that register holds the return 164 // address on entry to the function. So establish an initial .ra 165 // rule citing the return address register. 166 if (return_address_ < register_names_.size()) 167 entry_->initial_rules[ra_name_] = register_names_[return_address_]; 168 169 return true; 170 } 171 172 string DwarfCFIToModule::RegisterName(int i) { 173 assert(entry_); 174 if (i < 0) { 175 assert(i == kCFARegister); 176 return cfa_name_; 177 } 178 unsigned reg = i; 179 if (reg == return_address_) 180 return ra_name_; 181 182 // Ensure that a non-empty name exists for this register value. 183 if (reg < register_names_.size() && !register_names_[reg].empty()) 184 return register_names_[reg]; 185 186 reporter_->UnnamedRegister(entry_offset_, reg); 187 char buf[30]; 188 sprintf(buf, "unnamed_register%u", reg); 189 return buf; 190 } 191 192 void DwarfCFIToModule::Record(Module::Address address, int reg, 193 const string &rule) { 194 assert(entry_); 195 196 // Place the name in our global set of strings, and then use the string 197 // from the set. Even though the assignment looks like a copy, all the 198 // major std::string implementations use reference counting internally, 199 // so the effect is to have all our data structures share copies of rules 200 // whenever possible. Since register names are drawn from a 201 // vector<string>, register names are already shared. 202 string shared_rule = *common_strings_.insert(rule).first; 203 204 // Is this one of this entry's initial rules? 205 if (address == entry_->address) 206 entry_->initial_rules[RegisterName(reg)] = shared_rule; 207 // File it under the appropriate address. 208 else 209 entry_->rule_changes[address][RegisterName(reg)] = shared_rule; 210 } 211 212 bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { 213 reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); 214 // Treat this as a non-fatal error. 215 return true; 216 } 217 218 bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { 219 ostringstream s; 220 s << RegisterName(reg); 221 Record(address, reg, s.str()); 222 return true; 223 } 224 225 bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, 226 int base_register, long offset) { 227 ostringstream s; 228 s << RegisterName(base_register) << " " << offset << " + ^"; 229 Record(address, reg, s.str()); 230 return true; 231 } 232 233 bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, 234 int base_register, long offset) { 235 ostringstream s; 236 s << RegisterName(base_register) << " " << offset << " +"; 237 Record(address, reg, s.str()); 238 return true; 239 } 240 241 bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, 242 int base_register) { 243 ostringstream s; 244 s << RegisterName(base_register); 245 Record(address, reg, s.str()); 246 return true; 247 } 248 249 bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, 250 const string &expression) { 251 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); 252 // Treat this as a non-fatal error. 253 return true; 254 } 255 256 bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, 257 const string &expression) { 258 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); 259 // Treat this as a non-fatal error. 260 return true; 261 } 262 263 bool DwarfCFIToModule::End() { 264 module_->AddStackFrameEntry(entry_); 265 entry_ = NULL; 266 return true; 267 } 268 269 void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { 270 fprintf(stderr, "%s, section '%s': " 271 "the call frame entry at offset 0x%zx refers to register %d," 272 " whose name we don't know\n", 273 file_.c_str(), section_.c_str(), offset, reg); 274 } 275 276 void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, 277 const string ®) { 278 fprintf(stderr, "%s, section '%s': " 279 "the call frame entry at offset 0x%zx sets the rule for " 280 "register '%s' to 'undefined', but the Breakpad symbol file format" 281 " cannot express this\n", 282 file_.c_str(), section_.c_str(), offset, reg.c_str()); 283 } 284 285 void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, 286 const string ®) { 287 fprintf(stderr, "%s, section '%s': " 288 "the call frame entry at offset 0x%zx uses a DWARF expression to" 289 " describe how to recover register '%s', " 290 " but this translator cannot yet translate DWARF expressions to" 291 " Breakpad postfix expressions\n", 292 file_.c_str(), section_.c_str(), offset, reg.c_str()); 293 } 294 295 } // namespace google_breakpad 296