/ src / common / dwarf_cfi_to_module.cc
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