Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 // -*- mode: c++ -*-
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.
32 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
34 // Implementation of google_breakpad::DwarfCFIToModule.
35 // See dwarf_cfi_to_module.h for details.
37 #include <sstream>
38 #include <iomanip>
40 #include "common/dwarf_cfi_to_module.h"
41 #include "common/logging.h"
43 namespace google_breakpad {
45 using std::ostringstream;
47 vector<const UniqueString*> DwarfCFIToModule::RegisterNames::MakeVector(
48 const char* const* strings,
49 size_t size) {
50 vector<const UniqueString*> names(size, NULL);
51 for (size_t i = 0; i < size; ++i) {
52 names[i] = ToUniqueString(strings[i]);
53 }
55 return names;
56 }
58 vector<const UniqueString*> DwarfCFIToModule::RegisterNames::I386() {
59 static const char *const names[] = {
60 "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
61 "$eip", "$eflags", "$unused1",
62 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
63 "$unused2", "$unused3",
64 "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
65 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
66 "$fcw", "$fsw", "$mxcsr",
67 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
68 "$tr", "$ldtr"
69 };
71 return MakeVector(names, sizeof(names) / sizeof(names[0]));
72 }
74 vector<const UniqueString*> DwarfCFIToModule::RegisterNames::X86_64() {
75 static const char *const names[] = {
76 "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
77 "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
78 "$rip",
79 "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
80 "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
81 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
82 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
83 "$rflags",
84 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
85 "$fs.base", "$gs.base", "$unused3", "$unused4",
86 "$tr", "$ldtr",
87 "$mxcsr", "$fcw", "$fsw"
88 };
90 return MakeVector(names, sizeof(names) / sizeof(names[0]));
91 }
93 // Per ARM IHI 0040A, section 3.1
94 vector<const UniqueString*> DwarfCFIToModule::RegisterNames::ARM() {
95 static const char *const names[] = {
96 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
97 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
98 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
99 "fps", "cpsr", "", "", "", "", "", "",
100 "", "", "", "", "", "", "", "",
101 "", "", "", "", "", "", "", "",
102 "", "", "", "", "", "", "", "",
103 "", "", "", "", "", "", "", "",
104 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
105 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
106 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
107 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
108 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"
109 };
111 return MakeVector(names, sizeof(names) / sizeof(names[0]));
112 }
114 bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
115 uint8 version, const string &augmentation,
116 unsigned return_address) {
117 assert(!entry_);
119 // If dwarf2reader::CallFrameInfo can handle this version and
120 // augmentation, then we should be okay with that, so there's no
121 // need to check them here.
123 // Get ready to collect entries.
124 entry_ = new Module::StackFrameEntry;
125 entry_->address = address;
126 entry_->size = length;
127 entry_offset_ = offset;
128 return_address_ = return_address;
130 // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
131 // may not establish any rule for .ra if the return address column
132 // is an ordinary register, and that register holds the return
133 // address on entry to the function. So establish an initial .ra
134 // rule citing the return address register.
135 if (return_address_ < register_names_.size())
136 entry_->initial_rules[ustr__ZDra()]
137 = Module::Expr(register_names_[return_address_], 0, false);
139 return true;
140 }
142 const UniqueString* DwarfCFIToModule::RegisterName(int i) {
143 assert(entry_);
144 if (i < 0) {
145 assert(i == kCFARegister);
146 return ustr__ZDcfa();
147 }
148 unsigned reg = i;
149 if (reg == return_address_)
150 return ustr__ZDra();
152 // Ensure that a non-empty name exists for this register value.
153 if (reg < register_names_.size() && register_names_[reg] != ustr__empty())
154 return register_names_[reg];
156 reporter_->UnnamedRegister(entry_offset_, reg);
157 char buf[30];
158 sprintf(buf, "unnamed_register%u", reg);
159 return ToUniqueString(buf);
160 }
162 void DwarfCFIToModule::Record(Module::Address address, int reg,
163 const Module::Expr &rule) {
164 assert(entry_);
166 // Is this one of this entry's initial rules?
167 if (address == entry_->address)
168 entry_->initial_rules[RegisterName(reg)] = rule;
169 // File it under the appropriate address.
170 else
171 entry_->rule_changes[address][RegisterName(reg)] = rule;
172 }
174 bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
175 reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
176 // Treat this as a non-fatal error.
177 return true;
178 }
180 bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
181 // reg + 0
182 Module::Expr rule
183 = Module::Expr(RegisterName(reg), 0, false);
184 Record(address, reg, rule);
185 return true;
186 }
188 bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
189 int base_register, long offset) {
190 // *(base_register + offset)
191 Module::Expr rule
192 = Module::Expr(RegisterName(base_register), offset, true);
193 Record(address, reg, rule);
194 return true;
195 }
197 bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
198 int base_register, long offset) {
199 // base_register + offset
200 Module::Expr rule
201 = Module::Expr(RegisterName(base_register), offset, false);
202 Record(address, reg, rule);
203 return true;
204 }
206 bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
207 int base_register) {
208 // base_register + 0
209 Module::Expr rule
210 = Module::Expr(RegisterName(base_register), 0, false);
211 Record(address, reg, rule);
212 return true;
213 }
215 bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
216 const string &expression) {
217 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
218 // Treat this as a non-fatal error.
219 return true;
220 }
222 bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
223 const string &expression) {
224 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
225 // Treat this as a non-fatal error.
226 return true;
227 }
229 bool DwarfCFIToModule::End() {
230 module_->AddStackFrameEntry(entry_);
231 entry_ = NULL;
232 return true;
233 }
235 void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
236 BPLOG(INFO) << file_ << ", section '" << section_
237 << "': the call frame entry at offset 0x"
238 << std::setbase(16) << offset << std::setbase(10)
239 << " refers to register " << reg << ", whose name we don't know";
240 }
242 void DwarfCFIToModule::Reporter::UndefinedNotSupported(
243 size_t offset,
244 const UniqueString* reg) {
245 BPLOG(INFO) << file_ << ", section '" << section_
246 << "': the call frame entry at offset 0x"
247 << std::setbase(16) << offset << std::setbase(10)
248 << " sets the rule for register '" << FromUniqueString(reg)
249 << "' to 'undefined', but the Breakpad symbol file format cannot "
250 << " express this";
251 }
253 void DwarfCFIToModule::Reporter::ExpressionsNotSupported(
254 size_t offset,
255 const UniqueString* reg) {
256 static uint64_t n_complaints = 0; // This isn't threadsafe
257 n_complaints++;
258 if (!is_power_of_2(n_complaints))
259 return;
260 BPLOG(INFO) << file_ << ", section '" << section_
261 << "': the call frame entry at offset 0x"
262 << std::setbase(16) << offset << std::setbase(10)
263 << " uses a DWARF expression to describe how to recover register '"
264 << FromUniqueString(reg) << "', but this translator cannot yet "
265 << "translate DWARF expressions to Breakpad postfix expressions (shown "
266 << n_complaints << " times)";
267 }
269 } // namespace google_breakpad