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 <[email protected]> <[email protected]>
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
MakeVector(const char * const * strings,size_t size)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
I386()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
X86_64()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
ARM()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
ARM64()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
MIPS()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
RISCV()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
Entry(size_t offset,uint64_t address,uint64_t length,uint8_t version,const string & augmentation,unsigned return_address)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
RegisterName(int i)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
Record(Module::Address address,int reg,const string & rule)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
UndefinedRule(uint64_t address,int reg)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
SameValueRule(uint64_t address,int reg)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
OffsetRule(uint64_t address,int reg,int base_register,long offset)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
ValOffsetRule(uint64_t address,int reg,int base_register,long offset)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
RegisterRule(uint64_t address,int reg,int base_register)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
ExpressionRule(uint64_t address,int reg,const string & expression)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
ValExpressionRule(uint64_t address,int reg,const string & expression)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
End()289 bool DwarfCFIToModule::End() {
290 module_->AddStackFrameEntry(std::move(entry_));
291 return true;
292 }
293
Architecture()294 string DwarfCFIToModule::Architecture() {
295 return module_->architecture();
296 }
297
UnnamedRegister(size_t offset,int reg)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
UndefinedNotSupported(size_t offset,const string & reg)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
ExpressionsNotSupported(size_t offset,const string & reg)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
325