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@mozilla.com> <jimb@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 
MakeVector(const char * const * strings,size_t size)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 
I386()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 
X86_64()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
ARM()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
ARM64()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 
MIPS()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 
Entry(size_t offset,uint64 address,uint64 length,uint8 version,const string & augmentation,unsigned return_address)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 
RegisterName(int i)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 
Record(Module::Address address,int reg,const string & rule)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 
UndefinedRule(uint64 address,int reg)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 
SameValueRule(uint64 address,int reg)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 
OffsetRule(uint64 address,int reg,int base_register,long offset)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 
ValOffsetRule(uint64 address,int reg,int base_register,long offset)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 
RegisterRule(uint64 address,int reg,int base_register)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 
ExpressionRule(uint64 address,int reg,const string & expression)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 
ValExpressionRule(uint64 address,int reg,const string & expression)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 
End()263 bool DwarfCFIToModule::End() {
264   module_->AddStackFrameEntry(entry_);
265   entry_ = NULL;
266   return true;
267 }
268 
UnnamedRegister(size_t offset,int reg)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 
UndefinedNotSupported(size_t offset,const string & reg)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 
ExpressionsNotSupported(size_t offset,const string & reg)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