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
41namespace google_breakpad {
42
43using std::ostringstream;
44
45vector<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
52vector<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
68vector<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
88vector<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
109vector<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
128vector<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
145bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
146 uint8_t version, const string& augmentation,
147 unsigned return_address) {
148 assert(!entry_);
149
150 // If 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
172string 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
192void 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 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
212bool DwarfCFIToModule::UndefinedRule(uint64_t address, int reg) {
213 reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
214 // Treat this as a non-fatal error.
215 return true;
216}
217
218bool DwarfCFIToModule::SameValueRule(uint64_t address, int reg) {
219 ostringstream s;
220 s << RegisterName(reg);
221 Record(address, reg, s.str());
222 return true;
223}
224
225bool DwarfCFIToModule::OffsetRule(uint64_t 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
233bool DwarfCFIToModule::ValOffsetRule(uint64_t 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
241bool DwarfCFIToModule::RegisterRule(uint64_t 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
249bool DwarfCFIToModule::ExpressionRule(uint64_t 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
256bool DwarfCFIToModule::ValExpressionRule(uint64_t 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
263bool DwarfCFIToModule::End() {
264 module_->AddStackFrameEntry(entry_);
265 entry_ = NULL;
266 return true;
267}
268
269void 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
276void 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
285void 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