Home | History | Annotate | Download | only in common
      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 &reg) {
    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 &reg) {
    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