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