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 | |
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 | |
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 | |
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 |
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 | |
108 | // Per ARM IHI 0057A, section 3.1 |
109 | vector<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 | |
128 | vector<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 | |
145 | bool 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 | |
172 | string 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 | |
192 | void 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 | |
212 | bool 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 | |
218 | bool 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 | |
225 | bool 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 | |
233 | bool 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 | |
241 | bool 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 | |
249 | bool 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 | |
256 | bool 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 | |
263 | bool DwarfCFIToModule::End() { |
264 | module_->AddStackFrameEntry(entry_); |
265 | entry_ = NULL; |
266 | return true; |
267 | } |
268 | |
269 | void 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 | |
276 | void 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 | |
285 | void 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 | |