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
MIPS()108 vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
109 static const char* const kRegisterNames[] = {
110 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
111 "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
112 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
113 "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
114 "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5",
115 "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13",
116 "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20",
117 "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
118 "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir"
119 };
120
121 return MakeVector(kRegisterNames,
122 sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
123 }
124
Entry(size_t offset,uint64 address,uint64 length,uint8 version,const string & augmentation,unsigned return_address)125 bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
126 uint8 version, const string &augmentation,
127 unsigned return_address) {
128 assert(!entry_);
129
130 // If dwarf2reader::CallFrameInfo can handle this version and
131 // augmentation, then we should be okay with that, so there's no
132 // need to check them here.
133
134 // Get ready to collect entries.
135 entry_ = new Module::StackFrameEntry;
136 entry_->address = address;
137 entry_->size = length;
138 entry_offset_ = offset;
139 return_address_ = return_address;
140
141 // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
142 // may not establish any rule for .ra if the return address column
143 // is an ordinary register, and that register holds the return
144 // address on entry to the function. So establish an initial .ra
145 // rule citing the return address register.
146 if (return_address_ < register_names_.size())
147 entry_->initial_rules[ra_name_] = register_names_[return_address_];
148
149 return true;
150 }
151
RegisterName(int i)152 string DwarfCFIToModule::RegisterName(int i) {
153 assert(entry_);
154 if (i < 0) {
155 assert(i == kCFARegister);
156 return cfa_name_;
157 }
158 unsigned reg = i;
159 if (reg == return_address_)
160 return ra_name_;
161
162 // Ensure that a non-empty name exists for this register value.
163 if (reg < register_names_.size() && !register_names_[reg].empty())
164 return register_names_[reg];
165
166 reporter_->UnnamedRegister(entry_offset_, reg);
167 char buf[30];
168 sprintf(buf, "unnamed_register%u", reg);
169 return buf;
170 }
171
Record(Module::Address address,int reg,const string & rule)172 void DwarfCFIToModule::Record(Module::Address address, int reg,
173 const string &rule) {
174 assert(entry_);
175
176 // Place the name in our global set of strings, and then use the string
177 // from the set. Even though the assignment looks like a copy, all the
178 // major std::string implementations use reference counting internally,
179 // so the effect is to have all our data structures share copies of rules
180 // whenever possible. Since register names are drawn from a
181 // vector<string>, register names are already shared.
182 string shared_rule = *common_strings_.insert(rule).first;
183
184 // Is this one of this entry's initial rules?
185 if (address == entry_->address)
186 entry_->initial_rules[RegisterName(reg)] = shared_rule;
187 // File it under the appropriate address.
188 else
189 entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
190 }
191
UndefinedRule(uint64 address,int reg)192 bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
193 reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
194 // Treat this as a non-fatal error.
195 return true;
196 }
197
SameValueRule(uint64 address,int reg)198 bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
199 ostringstream s;
200 s << RegisterName(reg);
201 Record(address, reg, s.str());
202 return true;
203 }
204
OffsetRule(uint64 address,int reg,int base_register,long offset)205 bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
206 int base_register, long offset) {
207 ostringstream s;
208 s << RegisterName(base_register) << " " << offset << " + ^";
209 Record(address, reg, s.str());
210 return true;
211 }
212
ValOffsetRule(uint64 address,int reg,int base_register,long offset)213 bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
214 int base_register, long offset) {
215 ostringstream s;
216 s << RegisterName(base_register) << " " << offset << " +";
217 Record(address, reg, s.str());
218 return true;
219 }
220
RegisterRule(uint64 address,int reg,int base_register)221 bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
222 int base_register) {
223 ostringstream s;
224 s << RegisterName(base_register);
225 Record(address, reg, s.str());
226 return true;
227 }
228
ExpressionRule(uint64 address,int reg,const string & expression)229 bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
230 const string &expression) {
231 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
232 // Treat this as a non-fatal error.
233 return true;
234 }
235
ValExpressionRule(uint64 address,int reg,const string & expression)236 bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
237 const string &expression) {
238 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
239 // Treat this as a non-fatal error.
240 return true;
241 }
242
End()243 bool DwarfCFIToModule::End() {
244 module_->AddStackFrameEntry(entry_);
245 entry_ = NULL;
246 return true;
247 }
248
UnnamedRegister(size_t offset,int reg)249 void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
250 fprintf(stderr, "%s, section '%s': "
251 "the call frame entry at offset 0x%zx refers to register %d,"
252 " whose name we don't know\n",
253 file_.c_str(), section_.c_str(), offset, reg);
254 }
255
UndefinedNotSupported(size_t offset,const string & reg)256 void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
257 const string ®) {
258 fprintf(stderr, "%s, section '%s': "
259 "the call frame entry at offset 0x%zx sets the rule for "
260 "register '%s' to 'undefined', but the Breakpad symbol file format"
261 " cannot express this\n",
262 file_.c_str(), section_.c_str(), offset, reg.c_str());
263 }
264
ExpressionsNotSupported(size_t offset,const string & reg)265 void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
266 const string ®) {
267 fprintf(stderr, "%s, section '%s': "
268 "the call frame entry at offset 0x%zx uses a DWARF expression to"
269 " describe how to recover register '%s', "
270 " but this translator cannot yet translate DWARF expressions to"
271 " Breakpad postfix expressions\n",
272 file_.c_str(), section_.c_str(), offset, reg.c_str());
273 }
274
275 } // namespace google_breakpad
276