toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:5f3266582610
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 #include <iomanip>
39
40 #include "common/dwarf_cfi_to_module.h"
41 #include "common/logging.h"
42
43 namespace google_breakpad {
44
45 using std::ostringstream;
46
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 }
54
55 return names;
56 }
57
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 };
70
71 return MakeVector(names, sizeof(names) / sizeof(names[0]));
72 }
73
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 };
89
90 return MakeVector(names, sizeof(names) / sizeof(names[0]));
91 }
92
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 };
110
111 return MakeVector(names, sizeof(names) / sizeof(names[0]));
112 }
113
114 bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
115 uint8 version, const string &augmentation,
116 unsigned return_address) {
117 assert(!entry_);
118
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.
122
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;
129
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);
138
139 return true;
140 }
141
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();
151
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];
155
156 reporter_->UnnamedRegister(entry_offset_, reg);
157 char buf[30];
158 sprintf(buf, "unnamed_register%u", reg);
159 return ToUniqueString(buf);
160 }
161
162 void DwarfCFIToModule::Record(Module::Address address, int reg,
163 const Module::Expr &rule) {
164 assert(entry_);
165
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 }
173
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 }
179
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 }
187
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 }
196
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 }
205
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 }
214
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 }
221
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 }
228
229 bool DwarfCFIToModule::End() {
230 module_->AddStackFrameEntry(entry_);
231 entry_ = NULL;
232 return true;
233 }
234
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 }
241
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 }
252
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 }
268
269 } // namespace google_breakpad

mercurial